package com.ruoyi.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.nio.charset.StandardCharsets;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;

public class WebSocketUtils extends WebSocketClient {
    private static WebSocketUtils wsclient = null;
    private String msg = "";

    public WebSocketUtils(URI serverURI) {
        super(serverURI);
    }

    public WebSocketUtils(URI serverUri, Map<String, String> headers, int connecttimeout) {
        super(serverUri, new Draft_6455(), headers, connecttimeout);
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
//        System.out.println("Connection established");
    }

    @Override
    public void onMessage(String s) {
//        System.out.println("Received message: " + s);
    }

    @Override
    public void onClose(int i, String s, boolean b) {
//        System.out.println("Connection closed");
    }

    @Override
    public void onError(Exception e) {
//        System.out.println("Error occurred: " + e.getMessage());
    }

    @Override
    public void onMessage(ByteBuffer socketBuffer) {
        try {
            byte[] compressed = new byte[socketBuffer.remaining()];
            socketBuffer.get(compressed);

            String market = uncompress(compressed).toLowerCase();
//            System.out.println("Uncompressed message: " + market);

            if (market.contains("ping")) {
//                System.out.println("Received ping message: " + market);
                String response = market.replace("ping", "pong");
                wsclient.send(response);
            } else {
                msg = market;
//                System.out.println("Received message set to msg: " + msg);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Map<String, String> getWebSocketHeaders() {
        return new HashMap<>();
    }

    private static void trustAllHosts(WebSocketUtils appClient) {
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[]{};
            }

            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }
        }};

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            appClient.setSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static WebSocketUtils executeWebSocket(String url) throws Exception {
        wsclient = new WebSocketUtils(new URI(url), getWebSocketHeaders(), 1000);
        trustAllHosts(wsclient);
        wsclient.connectBlocking();
        return wsclient;
    }

    public String byteBufferToString(ByteBuffer buffer) {
        try {
            Charset charset = StandardCharsets.UTF_8;
            CharsetDecoder decoder = charset.newDecoder();
            CharBuffer charBuffer = decoder.decode(buffer);
            buffer.flip();
            return charBuffer.toString();
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    public String uncompress(byte[] compressed) throws IOException {
        if (compressed == null || compressed.length == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(compressed);
        GZIPInputStream gunzip = new GZIPInputStream(in);
        byte[] buffer = new byte[256];
        int n;
        while ((n = gunzip.read(buffer)) >= 0) {
            out.write(buffer, 0, n);
        }
        return new String(out.toByteArray(), StandardCharsets.UTF_8);
    }

    public String getMsg() {
        return this.msg;
    }
    public void clearMsg() {
        this.msg = null;
    }
}